package com.systop.controller;

import com.systop.entity.SysUser;
import com.systop.component.SmsComponent;
import com.systop.constant.AuthServiceConstant;
import com.systop.domain.vo.UsersVo;
import com.systop.service.SysUserTokenService;
import com.systop.utils.BizCodeEnum;
import com.systop.service.CaptchaService;
import com.systop.service.SysUserService;
import com.systop.utils.R;
import com.systop.utils.RedisUtil;
import com.systop.domain.vo.LoginInfoVo;
import com.systop.domain.vo.CaptchaVo;
import com.systop.domain.to.SucLoginUserTo;
import com.systop.validator.group.AddGroup;
import com.systop.validator.group.LoginGroup;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

/**
 * @Description: TODO
 * @Author: jsj
 * @Date: 2023/1/29
 */
@Controller
public class LoginController{
    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private CaptchaService captchaService;

    @Autowired
    private SysUserTokenService sysUserTokenService;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private SmsComponent smsComponent;

    //登录页面验证登录
    @RequestMapping(value="/login", method=RequestMethod.GET)
    @ResponseBody
    public String toLogin() {
        return "login";
    }

    @RequestMapping(value="/userLogin", method= RequestMethod.POST)
    @ResponseBody
    public R userLogin(@Validated(value = LoginGroup.class) @RequestBody LoginInfoVo loginInfoVo){
        System.out.println(loginInfoVo);
        return validMethod(0,loginInfoVo);
    }

    @RequestMapping(value="/login", method= RequestMethod.POST)
    @ResponseBody
    public R login(@Validated(value = LoginGroup.class) @RequestBody LoginInfoVo loginInfoVo) {
        System.out.println(loginInfoVo);
        return validMethod(1,loginInfoVo);
    }

    private R validMethod(Integer methodStatus,LoginInfoVo loginInfoVo){
        //判断验证码是否正确
        boolean validate = captchaService.validate(
                loginInfoVo.getCaptchaEntity().getUuid(),
                loginInfoVo.getCaptchaEntity().getCode());
        if (!validate){
            return R.error(BizCodeEnum.VERIFICATION_CODE_ERROR.getMsg());
        }

        Map<String, Object> map = new HashMap<String, Object>();
        SysUser loginingUser = sysUserService.findUserByUserCode(loginInfoVo.getUserCode());

        /**
         * 判断用户是否存在
         */
        if (loginingUser == null) {
            return R.error(BizCodeEnum.USERNAME_OR_PASSWORD_ERROR.getMsg());
        }

        System.out.println(loginingUser);

        if (methodStatus == 1){
            /**
             * 权限判断
             * methodStatus的参数为1时为后台登录系统
             *
             */
            if(loginingUser.getRole()!=1 && loginingUser.getRole()!=2){
                return R.error(
                        BizCodeEnum.USER_NOT_ADMIN.getCode(),
                        BizCodeEnum.USER_NOT_ADMIN.getMsg());
            }
        }


        /**
         * 密码解密验证
         */
        if(!loginingUser.getUserPass().equals(
                new Sha256Hash(loginInfoVo.getUserPass(),loginingUser.getSalt()).toHex())){
            return R.error(
                    BizCodeEnum.PASSWORD_VALID_ERROR.getCode(),
                    BizCodeEnum.PASSWORD_VALID_ERROR.getMsg());
        }

        //创建更新token
        R r = sysUserTokenService.createToken(loginingUser.getUserId());

        SucLoginUserTo sucLoginUserTo = new SucLoginUserTo();
        BeanUtils.copyProperties(loginingUser, sucLoginUserTo);
        sucLoginUserTo.setToken(r.get("token").toString());

        if (methodStatus == 1){
            redisUtil.set(
                    AuthServiceConstant.LOGINING_USER + sucLoginUserTo.getUserCode(),
                    sucLoginUserTo,
                    60000);
            r.put("info",sucLoginUserTo).put("msg","登录成功!");
        }else{
            redisUtil.set(
                    AuthServiceConstant.LOGINING_VISITOR + sucLoginUserTo.getUserCode(),
                    sucLoginUserTo,
                    60000);
            r.put("visitorInfo",sucLoginUserTo).put("msg","登录成功!");
        }
        return R.ok(r);
    }

    /**
     * 退出登录
     * @param sucLoginUserTo
     * @return
     */
    @RequestMapping(value = "/userLoginOut",method = RequestMethod.POST)
    @ResponseBody
    public R userLoginOut(@RequestBody SucLoginUserTo sucLoginUserTo){
        System.out.println(sucLoginUserTo);
        return getR(0,sucLoginUserTo);
    }

    @RequestMapping(value = "/loginOut",method = RequestMethod.POST)
    @ResponseBody
    public R loginOut(@RequestBody SucLoginUserTo sucLoginUserTo){
        System.out.println(sucLoginUserTo);
        return getR(1,sucLoginUserTo);
    }

    private R getR(Integer methodStatus,SucLoginUserTo sucLoginUserTo) {
        if (sucLoginUserTo == null) {
            return R.error();
        }

        SysUser loginingUser = sysUserService.findUserByUserCode(sucLoginUserTo.getUserCode());
        /**
         * 判断用户是否存在
         */
        if (loginingUser == null) {
            return R.error(BizCodeEnum.UNDEFINED_ERROR.getMsg());
        }


        //修改token
        sysUserTokenService.logout(loginingUser.getUserId());

        if (methodStatus == 1) {
            redisUtil.del(AuthServiceConstant.LOGINING_USER + sucLoginUserTo.getUserCode());
        }else{
            redisUtil.del(AuthServiceConstant.LOGINING_VISITOR + sucLoginUserTo.getUserCode());
        }
        return R.ok();
    }


    /**
     * 判断当前用户是否在线
     * @param sucLoginUserTo
     * @return
     */
    @RequestMapping(value = "/isOnline",method = RequestMethod.POST)
    @ResponseBody
    public R isOnline(@RequestBody SucLoginUserTo sucLoginUserTo){
        // System.out.println(sucLoginUserTo);
        Object o = redisUtil.get(AuthServiceConstant.LOGINING_USER + sucLoginUserTo.getUserCode());

        if(o != null){
            return R.ok(BizCodeEnum.IS_ONLINE.getMsg());
        }else {
            return R.ok(BizCodeEnum.NOT_ONLINE.getMsg());
        }
    }

    /**
     * 获取手机验证码
     * @param captchaVo
     * @return
     */
    @RequestMapping(value = "/sms/sendCode",method = RequestMethod.POST)
    @ResponseBody
    public R getPhoneMsgCode(@RequestBody CaptchaVo captchaVo){
        String mobile = captchaVo.getUserPhone();
        System.out.println(mobile);

        //用于手机号验证，验证手机号是否合法
        if (mobile==null
                || !Pattern.matches("^1[3-9]\\d{9}$", mobile)) {
            return R.error(BizCodeEnum.ILLEGAL_PHONE_EXCEPTION.getCode()
                    ,BizCodeEnum.ILLEGAL_PHONE_EXCEPTION.getMsg());
        }

        // TODO: 2022/6/9 1、接口防刷
        //1、判断当前手机号是否在有效期内持有验证码
        String redisCode = !captchaVo.isUpdate() ?
                stringRedisTemplate.opsForValue().get(AuthServiceConstant.SMS_CODE_CACHE_PREFIX + mobile)
                :stringRedisTemplate.opsForValue().get(AuthServiceConstant.SMS_CODE_CACHE_UPDATE_PREFIX + mobile);

        if (!StringUtils.isEmpty(redisCode) && redisCode !="") {
            long l = Long.parseLong(redisCode.split("_")[1]);
            //60s内不能再次发送
            if(System.currentTimeMillis() - l < 60000){
                return R.error(BizCodeEnum.SMS_CODE_EXCEPTION.getCode(),
                        BizCodeEnum.SMS_CODE_EXCEPTION.getMsg());
            }
        }

        //2、验证码的再次校验。redis。存key-mobile，value-authCode
        //生成六位数验证码  数字验证码
        String authCode = String.valueOf(new Random().nextInt(899999) + 100000);
        redisCode = authCode + "_" + System.currentTimeMillis();

        //redis缓存验证码，防止同一个mobile在60s内再次发送验证码
        String prefix = captchaVo.isUpdate() ? AuthServiceConstant.SMS_CODE_CACHE_UPDATE_PREFIX : AuthServiceConstant.SMS_CODE_CACHE_PREFIX;
        stringRedisTemplate.opsForValue()
                .set(prefix + mobile, redisCode,
                        10, TimeUnit.MINUTES);

        System.out.println("发送验证码:"+mobile+"--->"+authCode);

        //调用发送手机验证码组件
        smsComponent.sendSmsCode(mobile,authCode);

        return R.ok(BizCodeEnum.SMS_CODE_SENDED.getMsg());
    }

    /**
     * 注册
     * @param usersVo
     * @return
     */
    @RequestMapping(value = "/sms/register",method = RequestMethod.POST)
    @ResponseBody
    public R register(@Validated(AddGroup.class) @RequestBody UsersVo usersVo){
        System.out.println(usersVo);

        //1、校验验证码
        String phoneCaptcha = usersVo.getPhoneCaptcha();
        String s = stringRedisTemplate.opsForValue().get(AuthServiceConstant.SMS_CODE_CACHE_PREFIX + usersVo.getUserPhone());

        System.out.println("当前手机号："+ usersVo.getUserPhone()
                + "-----> 输入:" + usersVo.getPhoneCaptcha()
                + "-----> 查询:" + s);

        // System.out.println(s.split("_")[0]);

        if (!StringUtils.isEmpty(s)){
            if (phoneCaptcha.equals(s.split("_")[0])) {
                //使用验证码后删除redis中的验证码   令牌机制
                stringRedisTemplate.delete(AuthServiceConstant.SMS_CODE_CACHE_PREFIX + usersVo.getUserPhone());
                //注册方法
                if (sysUserService.registerUser(usersVo)) {
                    //注册成功
                    return R.ok();
                }
            }
        }
        //注册失败，验证码错误
        return R.error(BizCodeEnum.PHONE_CAPTCHA_EXCEPTION.getCode()
                ,BizCodeEnum.PHONE_CAPTCHA_EXCEPTION.getMsg());
    }
}
